package com.boom.monitor.service;

import cn.hutool.core.date.DateUtil;
import com.boom.common.utils.DateUtils;
import com.boom.common.utils.EncryptionUtils;
import com.boom.monitor.DTO.VmwareDTO;
import com.boom.monitor.VO.vmware.BoomAboutInfo;
import com.boom.monitor.VO.vmware.BoomDataStore;
import com.boom.monitor.VO.vmware.BoomHostSystem;
import com.boom.monitor.VO.vmware.BoomVirtualMachine;
import com.vmware.vim25.*;
import com.vmware.vim25.mo.*;

import java.net.URL;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import static com.boom.monitor.util.FormatterUnitUtils.formatterG;

/**
 * @author:yzw
 * @Date:2021/2/25 下午2:37
 * @desc:
 * @version:1.0
 */
public class BoomVmwareService {

	/**
	 * 获取vmware信息
	 *
	 * @param dto
	 * @return com.boom.monitor.VO.vmware.BoomHostSystem
	 * @author yzw
	 * @time 2021/4/1 下午2:03
	 */
	public static BoomHostSystem getVmware(VmwareDTO dto) {
		ServiceInstance si = null;
		BoomHostSystem boomHostSystem = new BoomHostSystem();
		try {
			String password = EncryptionUtils.atob(dto.getPassword());
			si = new ServiceInstance(new URL("https", dto.getIp(), "/sdk"), dto.getUsername(), password, true);
			Folder rootFolder = si.getRootFolder();
			ManagedEntity[] managedEntities = new InventoryNavigator(rootFolder).searchManagedEntities("HostSystem");
			if (managedEntities == null || managedEntities.length == 0) {
				si.getServerConnection().logout();
			}
			assert managedEntities != null;
			HostSystem hostSystem = (HostSystem) managedEntities[0];
			// 存储信息
			boomHostSystem.setBoomDataStores(getDataStores(hostSystem));
			// 主机信息
			boomHostSystem.setAboutInfo(getBoomAboutInfo(hostSystem, si, dto.getIp()));
			// 虚拟机信息
			boomHostSystem.setBoomVirtualMachines(getVirtualMachines(si));
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		} finally {
			if (si != null) {
				si.getServerConnection().logout();
			}
		}
		return boomHostSystem;
	}

	/**
	 * 主机信息
	 *
	 * @param hostSystem
	 * @param si
	 * @param ip
	 * @return com.boom.monitor.VO.vmware.BoomAboutInfo
	 * @author yzw
	 * @time 2021/3/31 上午11:33
	 */
	private static BoomAboutInfo getBoomAboutInfo(HostSystem hostSystem, ServiceInstance si, String ip) {
		HostHardwareInfo systemHardware = hostSystem.getHardware();
		BoomAboutInfo aboutInfo = new BoomAboutInfo();
		// 总内存情况
		aboutInfo.setMemTotal(formatterG(systemHardware.getMemorySize(), 1024 * 1024 * 1024));
		aboutInfo.setMemUsed(formatterG(hostSystem.getSummary().getQuickStats().overallMemoryUsage, 1024));
		// CPU个数
		aboutInfo.setCpuNum(hostSystem.getSummary().getHardware().getNumCpuCores());
		long runTime = DateUtil.betweenDay(hostSystem.getRuntime().getBootTime().getTime(), new Date(), true);
		// 运行时间
		aboutInfo.setRunTime(runTime);
		aboutInfo.setVersion(si.getAboutInfo().getVersion());
		aboutInfo.setName(si.getAboutInfo().getFullName());
		HostBIOSInfo biosInfo = systemHardware.getBiosInfo();
		aboutInfo.setBiosVersion(biosInfo.getBiosVersion());
		aboutInfo.setBiosDate(DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss", biosInfo.getReleaseDate().getTime()));
		aboutInfo.setIp(ip);
		return aboutInfo;
	}

	/**
	 * 获取主机存储信息集合
	 *
	 * @param hostSystem
	 * @return java.util.List<com.boom.monitor.VO.vmware.BoomDataStore>
	 * @author yzw
	 * @time 2021/4/1 下午2:02
	 */
	private static List<BoomDataStore> getDataStores(HostSystem hostSystem) throws RemoteException {
		Datastore[] datastoreList = hostSystem.getDatastores();
		List<BoomDataStore> boomDataStores = new ArrayList<>();
		// 总存储情况
		for (Datastore datastore : datastoreList) {
			DatastoreSummary summary = datastore.getSummary();
			BoomDataStore boomDataStore = new BoomDataStore();
			boomDataStore.setName(summary.getName());
			boomDataStore.setType(summary.getType());
			boomDataStore.setDiskTotal(summary.getCapacity() / (1024 * 1024 * 1024) + "G");
			boomDataStore.setDiskFree(summary.getFreeSpace() / (1024 * 1024 * 1024) + "G");
			boomDataStores.add(boomDataStore);
		}
		return boomDataStores;
	}

	/**
	 * 获取虚拟机列表信息集合
	 *
	 * @param si
	 * @return java.util.List<com.boom.monitor.VO.vmware.BoomVirtualMachine>
	 * @author yzw
	 * @time 2021/4/1 下午2:02
	 */
	private static List<BoomVirtualMachine> getVirtualMachines(ServiceInstance si) throws RemoteException {
		ManagedEntity[] mes = new InventoryNavigator(si.getRootFolder()).searchManagedEntities("VirtualMachine");
		if (mes == null || mes.length == 0) {
			si.getServerConnection().logout();
		}
		assert mes != null;
		List<BoomVirtualMachine> boomVirtualMachines = new ArrayList<>();
		for (ManagedEntity me : mes) {
			BoomVirtualMachine boomVirtualMachine = new BoomVirtualMachine();
			VirtualMachine virtualMachine = (VirtualMachine) me;
			VirtualMachineConfigInfo config = virtualMachine.getConfig();
			VirtualHardware hardware = config.getHardware();
			boomVirtualMachine.setCpuNum(hardware.getNumCPU());
			boomVirtualMachine.setMemTotal(formatterG(hardware.getMemoryMB()));
			VirtualMachineQuickStats quickStats = virtualMachine.getSummary().getQuickStats();
			Integer hostMemoryUsage = quickStats.getHostMemoryUsage();
			if (hostMemoryUsage != null) {
				boomVirtualMachine.setMemUsed(formatterG(hostMemoryUsage, 1024));
			}
			boomVirtualMachine.setStatus(quickStats.getGuestHeartbeatStatus().name());
			boomVirtualMachine.setName(virtualMachine.getName());
			boomVirtualMachine.setDesc(config.getAnnotation());
			boomVirtualMachine.setIp(virtualMachine.getGuest().getIpAddress());
			VirtualDisk theDisk = null;
			VirtualDevice[] devices = hardware.getDevice();
			for (int i = 0; devices != null && i < devices.length; i++) {
				if (devices[i] instanceof VirtualDisk) {
					theDisk = (VirtualDisk) devices[i];
					break;
				}
			}
			if (theDisk != null) {
				boomVirtualMachine.setDiskTotal(formatterG(theDisk.getCapacityInKB(), 1024 * 1024));
			}
			VirtualMachineSummary virtualMachineSummary = virtualMachine.getSummary();
			VirtualMachineStorageSummary virtualMachineStorageSummary = virtualMachineSummary.storage;
			long total = virtualMachineStorageSummary.committed;
			boomVirtualMachine.setDiskUsed(formatterG(total, 1024 * 1024 * 1024));
			boomVirtualMachine.setOperateSystem(config.getGuestFullName());
			boomVirtualMachines.add(boomVirtualMachine);
		}
		return boomVirtualMachines;
	}
}
